﻿using PtzControl.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace PtzControl.Views
{
    /// <summary>
    /// WinPtzView.xaml 的交互逻辑
    /// </summary>
    public partial class WinPtzView : Window, INotifyPropertyChanged
    {
        #region 界面显示

        private string _targetName;
        /// <summary>
        /// 目标名称
        /// </summary>
        public string TargetName
        {
            get { return _targetName; }
            set
            {
                _targetName = value;
                NotifyOfPropertyChanged(() => TargetName);
            }
        }

        private bool _isPtzEnable;
        /// <summary>
        /// 是否可用
        /// 
        /// 由引用方设置
        /// </summary>
        public bool IsPtzEnable
        {
            get { return _isPtzEnable; }
            set
            {
                _isPtzEnable = value;
                NotifyOfPropertyChanged(() => IsPtzEnable);
            }
        }

        private PtzTips _tips;
        /// <summary>
        /// 下方提示字符
        /// </summary>
        public PtzTips Tips
        {
            get { return _tips; }
            set
            {
                _tips = value;
                NotifyOfPropertyChanged(() => Tips);

                if (!string.IsNullOrWhiteSpace(value?.Message))
                {
                    (_eraseTipsTimer ?? (_eraseTipsTimer = new Timer((s) =>
                    {
                        Tips = null;
                    }))).Change(3000, Timeout.Infinite);
                }
            }
        }

        private float _speed = 0.5f;
        /// <summary>
        /// 云台速度
        /// </summary>
        public float Speed
        {
            get { return _speed; }
            set
            {
                _speed = value;
                NotifyOfPropertyChanged(() => Speed);
            }
        }

        private bool _canZoom;

        public bool CanZoom
        {
            get { return _canZoom; }
            set
            {
                _canZoom = value;
                NotifyOfPropertyChanged(() => CanZoom);
            }
        }

        private bool _canIris;

        public bool CanIris
        {
            get { return _canIris; }
            set
            {
                _canIris = value;
                NotifyOfPropertyChanged(() => CanIris);
            }
        }

        private bool _canFocus;

        public bool CanFocus
        {
            get { return _canFocus; }
            set
            {
                _canFocus = value;
                NotifyOfPropertyChanged(() => CanFocus);
            }
        }

        private bool _canHome;

        public bool CanHome
        {
            get { return _canHome; }
            set
            {
                _canHome = value;
                NotifyOfPropertyChanged(() => CanHome);
            }
        }

        private bool _canPreset;

        public bool CanPreset
        {
            get { return _canPreset; }
            set
            {
                _canPreset = value;
                NotifyOfPropertyChanged(() => CanPreset);
            }
        }


        /// <summary>
        /// 擦除提示计时器
        /// </summary>
        private Timer _eraseTipsTimer;

        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        public WinPtzView()
        {
            InitializeComponent();
            _arrowButtons = new Dictionary<ArrowDirection, Button>()
            {
                { ArrowDirection.LEFT,btnLeft },
                { ArrowDirection.LEFT | ArrowDirection.UP,btnLeftUp},
                { ArrowDirection.UP,btnUp },
                { ArrowDirection.UP|ArrowDirection.RIGHT,btnRightUp},
                { ArrowDirection.RIGHT,btnRight},
                { ArrowDirection.RIGHT|ArrowDirection.DOWN,btnRightDown},
                { ArrowDirection.DOWN,btnDown},
                { ArrowDirection.DOWN|ArrowDirection.LEFT,btnLeftDown},
            };
        }

        ///// <summary>
        ///// 关闭时隐藏
        ///// </summary>
        ///// <param name="e"></param>
        //protected override void OnClosing(CancelEventArgs e)
        //{
        //    Hide();
        //    e.Cancel = true;
        //    base.OnClosing(e);
        //}


        /// <summary>
        /// 默认的预置位列表
        /// </summary>
        private List<string> _defaultPresetList = new List<string>() { "0", "1", "2", "3", "4", "5", "6", "7", "8" };

        private List<string> _presetList;
        /// <summary>
        /// 预置位列表
        /// </summary>
        public List<string> PresetList
        {
            get => _presetList;
            set
            {
                _presetList = value == null ? _defaultPresetList : value;
                NotifyOfPropertyChanged(() => PresetList);
                if (_presetList.Count > 0)
                {
                    SelectedPreset = 0;
                }
            }
        }

        private int _selectedPreset;
        /// <summary>
        /// 当前选中的预置位
        /// </summary>
        public int SelectedPreset
        {
            get { return _selectedPreset; }
            set
            {
                _selectedPreset = value;
                NotifyOfPropertyChanged(() => SelectedPreset);
            }
        }

        #region 界面通知

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyOfPropertyChanged<T>(Expression<Func<T>> expr)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(((MemberExpression)expr.Body).Member.Name));
        }

        #endregion

        /// <summary>
        /// 发送 ptz 命令事件
        /// </summary>
        public event Action<PtzCommand> SendPTZCommandEvent;

        /// <summary>
        /// 箭头集合
        /// </summary>
        private Dictionary<ArrowDirection, Button> _arrowButtons;

        #region 鼠标单击操作🖱

        private void btnLeftUp_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.LEFTUP, Value = Speed });
        }

        private void btnLeftUp_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.LEFTUP, Value = 0 });
        }

        private void btnUp_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.UP, Value = Speed });
        }

        private void btnUp_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.UP, Value = 0 });
        }

        private void btnRightUp_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.RIGHTUP, Value = Speed });
        }

        private void btnRightUp_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.RIGHTUP, Value = 0 });
        }

        private void btnLeft_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.LEFT, Value = Speed });
        }

        private void btnLeft_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.LEFT, Value = 0 });
        }

        private void btnHome_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.GOTOHOME });
            }
            else if (e.RightButton == MouseButtonState.Pressed)
            {
                SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.SETHOME });
            }
        }

        private void btnHome_MouseUp(object sender, MouseButtonEventArgs e)
        {

        }

        private void btnRight_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.RIGHT, Value = Speed });
        }

        private void btnRight_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.RIGHT, Value = 0 });
        }

        private void btnLeftDown_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.LEFTDOWN, Value = Speed });
        }

        private void btnLeftDown_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.LEFTDOWN, Value = 0 });
        }

        private void btnDown_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.DOWN, Value = Speed });
        }

        private void btnDown_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.DOWN, Value = 0 });
        }

        private void btnRightDown_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.RIGHTDOWN, Value = Speed });
        }

        private void btnRightDown_MouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.RIGHTDOWN, Value = 0 });
        }

        private void btnPlusFocus_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.FOCUS, Value = Speed });
        }

        private void btnPlusFocus_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.FOCUS, Value = 0 });
        }

        private void btnPlusZoom_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.ZOOM, Value = Speed });
        }

        private void btnPlusZoom_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.ZOOM, Value = 0 });
        }

        private void btnPlusAperture_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.APERTURE, Value = 0 });
        }

        private void btnPlusAperture_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.APERTURE, Value = Speed });
        }

        private void btnPreset_Click(object sender, RoutedEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.SETPRESET, Value = SelectedPreset });
        }

        private void btnGo_Click(object sender, RoutedEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.GOTOPRESET, Value = SelectedPreset });
        }

        private void btnMinusFocus_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.FOCUS, Value = -Speed });
        }

        private void btnMinusFocus_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.FOCUS, Value = -0 });
        }

        private void btnMinusZoom_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.ZOOM, Value = -Speed });
        }

        private void btnMinusZoom_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.ZOOM, Value = 0 });
        }

        private void btnMinusAperture_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.APERTURE, Value = -Speed });
        }

        private void btnMinusAperture_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            SendPTZCommandEvent?.Invoke(new PtzCommand() { Type = PtzType.APERTURE, Value = 0 });
        }

        #endregion

        #region 键盘操作⌨

        private ArrowDirection _lastState;

        private void ExecuteDirection(ArrowDirection direction, bool start)
        {
            if (_arrowButtons.TryGetValue(direction, out Button btn))
            {

                typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btn, new object[] { start });
                var routedEvent = start ? PreviewMouseDownEvent : PreviewMouseUpEvent;
                btn.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left)
                {
                    RoutedEvent = routedEvent,
                    Source = this,
                });
            }
        }

        private void StopAllDirection()
        {
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.LEFT, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.UP, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.RIGHT, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.DOWN, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.LEFTUP, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.RIGHTUP, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.LEFTDOWN, Value = 0 });
            //SendPTZCommandEvent?.Invoke(new PTZCommand() { Type = PTZType.RIGHTDOWN, Value = 0 });

            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnLeft, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnUp, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnRight, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnDown, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnLeftUp, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnLeftDown, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnRightUp, new object[] { false });
            typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(btnRightDown, new object[] { false });

        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            var oldState = _lastState;

            if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down)
            {
                switch (e.Key)
                {
                    case Key.Left:
                        if (_lastState.HasFlag(ArrowDirection.LEFT))
                        {
                            return;
                        }

                        if (_lastState.HasFlag(ArrowDirection.RIGHT))
                        {
                            _lastState ^= ArrowDirection.RIGHT;
                        }
                        _lastState |= ArrowDirection.LEFT;
                        break;

                    case Key.Right:
                        if (_lastState.HasFlag(ArrowDirection.RIGHT))
                        {
                            return;
                        }

                        if (_lastState.HasFlag(ArrowDirection.LEFT))
                        {
                            _lastState ^= ArrowDirection.LEFT;
                        }
                        _lastState |= ArrowDirection.RIGHT;
                        break;

                    case Key.Up:

                        if (_lastState.HasFlag(ArrowDirection.UP))
                        {
                            return;
                        }

                        if (_lastState.HasFlag(ArrowDirection.DOWN))
                        {
                            _lastState ^= ArrowDirection.DOWN;
                        }
                        _lastState |= ArrowDirection.UP;
                        break;

                    case Key.Down:

                        if (_lastState.HasFlag(ArrowDirection.DOWN))
                        {
                            return;
                        }

                        if (_lastState.HasFlag(ArrowDirection.UP))
                        {
                            _lastState ^= ArrowDirection.UP;
                        }
                        _lastState |= ArrowDirection.DOWN;
                        break;

                    default:
                        break;
                }

                ExecuteDirection(oldState, false);
                ExecuteDirection(_lastState, true);
            }
        }

        private void Window_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down)
            {
                var oldState = _lastState;

                switch (e.Key)
                {
                    case Key.Left:
                        if (_lastState.HasFlag(ArrowDirection.LEFT))
                        {
                            _lastState ^= ArrowDirection.LEFT;
                        }
                        break;

                    case Key.Right:
                        if (_lastState.HasFlag(ArrowDirection.RIGHT))
                        {
                            _lastState ^= ArrowDirection.RIGHT;
                        }
                        break;

                    case Key.Up:
                        if (_lastState.HasFlag(ArrowDirection.UP))
                        {
                            _lastState ^= ArrowDirection.UP;
                        }
                        break;

                    case Key.Down:
                        if (_lastState.HasFlag(ArrowDirection.DOWN))
                        {
                            _lastState ^= ArrowDirection.DOWN;
                        }
                        break;

                    default:
                        break;
                }

                if (oldState != _lastState)
                {
                    ExecuteDirection(oldState, false);
                    ExecuteDirection(_lastState, true);
                }

            }

        }

        #endregion

        #region 拖放操作

        private void Window_Drop(object sender, DragEventArgs e)
        {
            IsDragOver = false;
            Focus();
        }

        private bool _isDragOver;

        public bool IsDragOver
        {
            get { return _isDragOver; }
            set
            {
                _isDragOver = value;
                NotifyOfPropertyChanged(() => IsDragOver);
            }
        }

        private void Window_DragEnter(object sender, DragEventArgs e)
        {
            IsDragOver = true;
        }

        private void Window_DragLeave(object sender, DragEventArgs e)
        {
            IsDragOver = false;
        }

        #endregion


        public class PtzTips
        {
            public bool Success
            {
                get; set;
            }

            public string Message
            {
                get; set;
            }

            public PtzTips(bool success, string message)
            {
                Success = success;
                Message = message;
            }

        }



    }

    /// <summary>
    /// 箭头方向
    /// </summary>
    [Flags]
    public enum ArrowDirection
    {
        NONE = 0,
        LEFT = 1,
        UP = 2,
        RIGHT = 4,
        DOWN = 8,
    }

}